package de.tum.in.eist.im.client;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.gwt.cell.client.TextCell;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.cellview.client.CellList;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

import de.tum.in.eist.im.client.domain.Message;
import de.tum.in.eist.im.client.domain.User;

public class UI
{
    public enum windows
    {
        LOGIN, REGISTER, CHAT
    };

    private VerticalPanel login;
    private Label loginError;
    private TextBox nameLoginBox;
    private PasswordTextBox passwordLoginBox;

    private VerticalPanel register;
    private Label registerError;
    private TextBox nameRegisterBox;
    private PasswordTextBox passwordRegisterBox1;
    private PasswordTextBox passwordRegisterBox2;

    private VerticalPanel chat;
    private Label chatError;
    private FlexTable chatList;
    private CellList <String> userList;
    private TextBox message;
    private ScrollPanel chatWrapper;

    private Connector connector;
    private windows cur_window;

    public UI ()
    {
        connector = new Connector (this);

        initLoginWindow ();
        initRegisterWindow ();
        initChatWindow ();

        cur_window = windows.LOGIN;
        RootPanel.get ("eist_im_chat").add (login);
        nameLoginBox.setFocus (true);
    }

    /**
     * Sets an errormessage on current window
     * 
     * @param message
     *            ErrorMessage
     */
    public void setErrorMessage (String message)
    {
        Label error = getErrorLabel ();
        error.setText (message);
        error.setVisible (true);
    }

    /**
     * Clears errors on current window
     */
    public void clearErrorMessage ()
    {
        getErrorLabel ().setVisible (false);
    }

    /**
     * Gets the errorlabel for current window
     * 
     * @return Errorlabel
     */
    private Label getErrorLabel ()
    {
        switch (cur_window)
        {
            case LOGIN:
                return loginError;

            case REGISTER:
                return registerError;

            case CHAT:
                return chatError;
        }

        // This should never happen
        return null;
    }

    /**
     * Inits login window and handlers
     */
    private void initLoginWindow ()
    {
        login = new VerticalPanel ();
        loginError = new Label ();
        loginError.setVisible (false);
        Button loginButton = new Button ("Login");
        Button registerButton = new Button ("Register");

        // Username
        Label name_text = new Label ("Username:");
        nameLoginBox = new TextBox ();
        HorizontalPanel name = new HorizontalPanel ();
        name.add (name_text);
        name.add (nameLoginBox);

        // Passwort
        Label password_text = new Label ("Password:");
        passwordLoginBox = new PasswordTextBox ();
        HorizontalPanel password = new HorizontalPanel ();
        password.add (password_text);
        password.add (passwordLoginBox);

        // Error
        loginError.setStyleName ("errorMessage");
        loginError.setVisible (false);

        // Buttons
        HorizontalPanel links = new HorizontalPanel ();
        links.add (loginButton);
        links.add (registerButton);
        links.setSpacing (10);

        login.add (name);
        login.add (password);
        login.add (loginError);
        login.add (links);

        // Login-Button
        loginButton.addClickHandler (new ClickHandler ()
        {
            @Override
            public void onClick (ClickEvent event)
            {
                connector.login (nameLoginBox.getText (), passwordLoginBox.getText ());
            }
        });

        // Register-Button
        registerButton.addClickHandler (new ClickHandler ()
        {
            @Override
            public void onClick (ClickEvent event)
            {
                switchUI (windows.REGISTER);
            }
        });

        // "ENTER" in passwordBox => submit
        passwordLoginBox.addKeyPressHandler (new KeyPressHandler ()
        {
            @Override
            public void onKeyPress (KeyPressEvent event)
            {
                if (event.getCharCode () == KeyCodes.KEY_ENTER)
                {
                    connector.login (nameLoginBox.getText (), passwordLoginBox.getText ());
                }
            }
        });
    }

    /**
     * Inits register window and handlers
     */
    private void initRegisterWindow ()
    {
        register = new VerticalPanel ();
        registerError = new Label ();
        registerError.setVisible (false);
        Button registerButton = new Button ("Register");

        // Username
        Label nameText = new Label ("Username:");
        nameRegisterBox = new TextBox ();
        HorizontalPanel name = new HorizontalPanel ();
        name.add (nameText);
        name.add (nameRegisterBox);

        // Password 1
        Label password1Text = new Label ("Password:");
        passwordRegisterBox1 = new PasswordTextBox ();
        HorizontalPanel password1 = new HorizontalPanel ();
        password1.add (password1Text);
        password1.add (passwordRegisterBox1);

        // Password 2
        Label password2Text = new Label ("Repeat Password:");
        passwordRegisterBox2 = new PasswordTextBox ();
        HorizontalPanel password2 = new HorizontalPanel ();
        password2.add (password2Text);
        password2.add (passwordRegisterBox2);

        // Error
        registerError.setStyleName ("errorMessage");
        registerError.setVisible (false);

        // Button
        HorizontalPanel links = new HorizontalPanel ();
        links.add (registerButton);

        register.add (name);
        register.add (password1);
        register.add (password2);
        register.add (registerError);
        register.add (links);
        
        // Register-Button
        registerButton.addClickHandler (new ClickHandler()
        {            
            @Override
            public void onClick (ClickEvent event)
            {
                if (passwordRegisterBox1.getText ().equals (passwordRegisterBox2.getText ()))
                {
                    connector.register (nameRegisterBox.getText (), passwordRegisterBox1.getText ());
                }
                else
                {
                    setErrorMessage ("Passwords do not match");
                }
            }
        });
        
        // "ENTER" in passwordBox => submit
        passwordRegisterBox2.addKeyPressHandler (new KeyPressHandler ()
        {
            @Override
            public void onKeyPress (KeyPressEvent event)
            {
                if (event.getCharCode () == KeyCodes.KEY_ENTER)
                {
                    if (passwordRegisterBox1.getText ().equals (passwordRegisterBox2.getText ()))
                    {
                        connector.register (nameRegisterBox.getText (), passwordRegisterBox1.getText ());
                    }
                    else
                    {
                        setErrorMessage ("Passwords do not match");
                    }
                }
            }
        });
    }

    /**
     * Inits chat window and handlers
     */
    private void initChatWindow ()
    {
        chat = new VerticalPanel ();
        chatList = new FlexTable ();
        Button sendButton = new Button ("Send");
        userList = new CellList <String> (new TextCell ());
        Button logoutButton = new Button ("Logout");
        chatError = new Label ();
        chatError.setVisible (false);

        // Chatfenster scrollable
        HorizontalPanel main = new HorizontalPanel ();
        chatWrapper = new ScrollPanel ();
        chatWrapper.setStyleName ("chat_window");
        chatWrapper.add (chatList);

        userList.setHeight ("250px");

        // Add chat and userlist
        main.add (chatWrapper);
        main.add (userList);
        chat.add (main);

        chat.add (chatError);

        // Messages
        HorizontalPanel bot = new HorizontalPanel ();
        HorizontalPanel send_panel = new HorizontalPanel ();
        message = new TextBox ();
        message.addStyleName ("chat_textbox");
        // Logout
        send_panel.add (message);
        send_panel.add (sendButton);

        // Add msg and logout
        bot.add (send_panel);
        bot.add (logoutButton);

        chat.add (bot);
        
        // Send-Button
        sendButton.addClickHandler (new ClickHandler()
        {            
            @Override
            public void onClick (ClickEvent event)
            {
                if (message.getText ().equals (""))
                {                    
                    setErrorMessage ("Error: Empty Textbox");
                }
                else
                {
                    clearErrorMessage ();
                    connector.sendMessages (message.getText ());
                    message.setText ("");
                }
            }
        });
        
        // Logout-Button
        logoutButton.addClickHandler (new ClickHandler ()
        {
            @Override
            public void onClick (ClickEvent event)
            {
                connector.logout ();
            }
        });    
        
        // "ENTER" in Textbox
        message.addKeyPressHandler (new KeyPressHandler()
        {            
            @Override
            public void onKeyPress (KeyPressEvent event)
            {
                if (event.getCharCode () == KeyCodes.KEY_ENTER)
                {
                    if (message.getText ().equals (""))
                    {                    
                        setErrorMessage ("Error: Empty Textbox");
                    }
                    else
                    {
                        clearErrorMessage ();
                        connector.sendMessages (message.getText ());
                        message.setText ("");
                    }
                }
            }
        });
    }

    /**
     * Switch to specific UI IDs: 1 Login 2 Register 3 Chat
     * 
     * @param switch_to
     *            ID of UI
     */
    public void switchUI (windows to)
    {
        switch (to)
        {
            case LOGIN:
                //switch
                RootPanel.get ("eist_im_chat").remove (0);
                RootPanel.get ("eist_im_chat").add (login);
                
                // remove text
                nameLoginBox.setText ("");
                passwordLoginBox.setText ("");                
                
                // set focus
                nameLoginBox.setFocus (true);                
                break;

            case REGISTER:
                //switch
                RootPanel.get ("eist_im_chat").remove (0);
                RootPanel.get ("eist_im_chat").add (register);
                
                // remove text
                nameRegisterBox.setText ("");
                passwordRegisterBox1.setText (""); 
                passwordRegisterBox2.setText (""); 
                
                // set focus
                nameRegisterBox.setFocus (true);     
                break;

            case CHAT:
                //switch
                RootPanel.get ("eist_im_chat").remove (0);
                RootPanel.get ("eist_im_chat").add (chat);
                
                // remove text
                chatList.clear ();
                userList.setRowCount(0, true);
                userList.setRowData(0, new ArrayList<String>());
                
                // set focus
                message.setFocus (true);
                message.setText ("");
                break;
        }

        cur_window = to;
    }

    /**
     * Returns ConnectorClass
     * 
     * @return
     */
    public Connector getConnector ()
    {
        return connector;
    }
    
    public void updateUserlist (List <User> user)
    {
        ArrayList<String> usernames = new ArrayList<String> ();
        for (User u : user)
        {
            usernames.add (u.getUsername ());
        }
        userList.setRowCount (usernames.size(), true);
        userList.setRowData (0, usernames);
    }
    
    @SuppressWarnings ("deprecation")
    public void addMessage (Message msg)
    {   
        int row = chatList.getRowCount ();
        
        chatList.setWidget (row, 0, new Label (DateTimeFormat.getLongDateFormat().format (new Date (msg.getTimestamp ()))));
        chatList.setWidget (row, 1, new Label (msg.getSender ().getUsername ()));
        chatList.setWidget (row, 2, new Label (msg.getText ()));
        
        chatWrapper.scrollToBottom ();
    }
}
